import * as THREE from '../../build/three.module.js';
import Stats from '../../jsm/libs/stats.module.js';
import { TrackballControls } from '../../jsm/controls/TrackballControls.js';

const scene = new THREE.Scene();
scene.background = new THREE.Color(0x050505);

const camera = new THREE.PerspectiveCamera(45, innerWidth / innerHeight, 1, 10000);
camera.position.z = 480;
scene.add(camera);

scene.add(new THREE.AmbientLight(0xffffff, .2));

const pLight = new THREE.PointLight(0xffffff, .2);
camera.add(pLight);

// 构建网格模型
const createHeart = () => {
  const heartShape = new THREE.Shape();
  const x = 0, y = 0;

  heartShape.moveTo(x + 25, y + 25);
  heartShape.bezierCurveTo( x + 25, y + 25, x + 20, y, x, y );
  heartShape.bezierCurveTo( x - 30, y, x - 30, y + 35, x - 30, y + 35 );
  heartShape.bezierCurveTo( x - 30, y + 55, x - 10, y + 77, x + 25, y + 95 );
  heartShape.bezierCurveTo( x + 60, y + 77, x + 80, y + 55, x + 80, y + 35 );
  heartShape.bezierCurveTo( x + 80, y + 35, x + 80, y, x + 50, y );
  heartShape.bezierCurveTo( x + 35, y, x + 25, y + 25, x + 25, y + 25 );

  const extrudeOption = {
    depth: 16,
    bevelEnable: false,
    bevelSegments: 1,
    steps: 2,
    bevelSize: 1,
    bevelThickness: 1
  }
  const gmt = new THREE.ExtrudeGeometry(heartShape, extrudeOption);
  gmt.rotateX(Math.PI);
  gmt.scale(.4, .4, .4);
  return gmt;
}

const bufferGmt = new THREE.BufferGeometry(),
      
      radius = 125, // 球半径
      count = 80, // 心形数量

      positions = [],
      normals = [],
      colors = [],

      vector = new THREE.Vector3(),

      color = new THREE.Color(0xffffff),
      heartGmt = createHeart(),
      gmt = new THREE.Geometry();

for(let i = 1; i <= count; i += 1) {
  const phi = Math.acos( -1 + (2 * i) / count );
  const theta = Math.sqrt(count * Math.PI) * phi;
  
  vector.setFromSphericalCoords(radius, phi, theta);

  gmt.copy(heartGmt);
  gmt.lookAt(vector); // 本质已一次旋转，让几何体朝向指定点
  gmt.translate(vector.x, vector.y, vector.z);

  color.setHSL(i / count, 1, .7);

  gmt.faces.forEach(face => {
    positions.push( gmt.vertices[ face.a ].x );
    positions.push( gmt.vertices[ face.a ].y );
    positions.push( gmt.vertices[ face.a ].z );
    positions.push( gmt.vertices[ face.b ].x );
    positions.push( gmt.vertices[ face.b ].y );
    positions.push( gmt.vertices[ face.b ].z );
    positions.push( gmt.vertices[ face.c ].x );
    positions.push( gmt.vertices[ face.c ].y );
    positions.push( gmt.vertices[ face.c ].z );

    normals.push( face.normal.x );
    normals.push( face.normal.y );
    normals.push( face.normal.z );
    normals.push( face.normal.x );
    normals.push( face.normal.y );
    normals.push( face.normal.z );
    normals.push( face.normal.x );
    normals.push( face.normal.y );
    normals.push( face.normal.z );

    colors.push( color.r );
    colors.push( color.g );
    colors.push( color.b );
    colors.push( color.r );
    colors.push( color.g );
    colors.push( color.b );
    colors.push( color.r );
    colors.push( color.g );
    colors.push( color.b );
  })
}

bufferGmt.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
bufferGmt.setAttribute('normal', new THREE.Float32BufferAttribute(normals, 3));
bufferGmt.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));

const mtl = new THREE.MeshPhongMaterial({
  shininess: 80,
  vertexColors: THREE.VertexColors
});

const mesh = new THREE.Mesh(bufferGmt, mtl);
scene.add(mesh);

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(devicePixelRatio);
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);

const controls = new TrackballControls(camera, renderer.domElement);
controls.minDistance = 100;
controls.maxDistance = 800;
controls.dynamicDampingFactor = .1; // 动态阻尼因子

const stats = new Stats();
document.body.appendChild(stats.dom);

const animate = () => {
  requestAnimationFrame(animate);

  controls.update();
  stats.update();

  renderer.render(scene, camera);
}
animate();

const handleWindowResize = () => {
  camera.aspect = innerWidth / innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(innerWidth, innerHeight);
}
window.addEventListener('resize', handleWindowResize, false);